/*
 * Copyright @ 2024 weili23
 * com.sky.service.impl 16:50
 * All right reserved.
 */

package com.sky.service.impl;

import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.sky.constant.JwtClaimsConstant;
import com.sky.constant.MessageConstant;
import com.sky.entity.User;
import com.sky.exception.LoginFailedException;
import com.sky.mapper.UserMapper;
import com.sky.properties.JwtProperties;
import com.sky.service.UserService;
import com.sky.utils.JwtUtil;
import com.sky.vo.UserLoginVO;
import com.sky.vo.UserReportVO;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

/**
 * @desc:
 * @author: weili23
 * @createTime: 2024/10/31 16:50
 * @version: v1.0
 */
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {

    @Value("${sky.wechat.appid}")
    private String appid;
    @Value("${sky.wechat.secret}")
    private String secret;

    @Resource
    private UserMapper userMapper;
    @Resource
    private JwtProperties jwtProperties;

    private static final String LOGIN_URL = "https://api.weixin.qq.com/sns/jscode2session";
    @Override
    public UserLoginVO byCodeGetOpenid(String code) {
        UserLoginVO vo = new UserLoginVO();
        //1.根据授权码code调用微信接口
        String openid = getOpenid(code);
        if(openid ==null){
            throw new LoginFailedException(MessageConstant.LOGIN_FAILED);
        }
        // 否则 判断用户是否存在数据库中， 根据openid去查
        User user = this.lambdaQuery().eq(User::getOpenid, openid).one();
        if(user ==null){
            //插入新用户
            user = new User();
            user.setOpenid(openid);
            this.save(user);
        }
        //创建jwt令牌
        HashMap<String,Object> claim = new HashMap<>();
        claim.put(JwtClaimsConstant.USER_ID,user.getId());
        String token = JwtUtil.createJWT(jwtProperties.getUserSecretKey(), jwtProperties.getUserTtl(), claim);
        vo.setOpenid(openid);
        vo.setId(user.getId());
        vo.setToken(token);
        return vo;
    }

    private String getOpenid(String code){
        //1.根据授权码code调用微信接口
        HashMap<String, Object> map = new HashMap<>();
        map.put("js_code",code);
        map.put("appid",appid);
        map.put("secret",secret);
        map.put("grant_type","authorization_code");
        String response = HttpUtil.get(LOGIN_URL, map);
        //2.将返回的json字符串解析为对象
        JSONObject jsonObject = JSON.parseObject(response);
        String openid =jsonObject.containsKey("openid") ? jsonObject.getString("openid") : null;
        return openid;
    }

    @Override
    public UserReportVO getUserStatistics(LocalDate begin, LocalDate end) {
        //时间拼接成list
        List<LocalDate> timeList = new ArrayList<>();
        timeList.add(begin);
        while(!begin.equals(end)){
            begin =begin.plusDays(1);
            timeList.add(begin);
        }
        List<Integer> newUserList = new ArrayList<>();
        List<Integer> totalUserList = new ArrayList<>();
        //循环去查询每天的用户
        for (LocalDate localDate : timeList) {
            LocalDateTime startTime = localDate.atStartOfDay();
            LocalDateTime endTime = localDate.atTime(LocalTime.MAX);
            Integer newSum = userMapper.getUserStatistics(startTime,endTime);
            Integer sum = userMapper.getUserStatistics(null,endTime);
            newUserList.add(newSum);
            totalUserList.add(sum);
        }
        UserReportVO vo = UserReportVO.builder().dateList(StringUtils.join(timeList, ","))
                .newUserList(StringUtils.join(newUserList, ","))
                .totalUserList(StringUtils.join(totalUserList, ","))
                .build();
        return vo;
    }
}
